package com.zxq.ai.infrastructure.gateway;

import com.zxq.common.middleware.gateway.RedisLockGateway;
import com.zxq.common.middleware.lock.StoreKey;
import com.zxq.common.utils.NullUtil;
import jakarta.annotation.Resource;
import org.springframework.data.redis.connection.RedisCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class RedisLockGatewayImpl implements RedisLockGateway {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RedisCommands redisCommands;

    @Override
    public boolean compareAndSet(StoreKey key, String oldValue, String newValue, int expireTime) {

        byte[] keyBytes = SafeEncoder.encode(key.toString());
        byte[] oldValueBytes = SafeEncoder.encode(oldValue);
        byte[] newValueBytes = SafeEncoder.encode(newValue);
        byte[] expireTimeBytes = SafeEncoder.encode(String.valueOf(expireTime));

        Long result;
        if (expireTime > 0) {
            result = redisCommands.eval(
                    RedisScript.COMPARE_AND_SET_WITH_EXPIRE_BYTES,
                    ReturnType.INTEGER,
                    1,
                    keyBytes, oldValueBytes, newValueBytes, expireTimeBytes);
        } else {
            result = redisCommands.eval(
                    RedisScript.COMPARE_AND_SET_BYTES,
                    ReturnType.INTEGER,
                    1,
                    keyBytes, oldValueBytes, newValueBytes);
        }

        result = NullUtil.defaultIfNull(result, 0L);
        return result == 1;
    }

    @Override
    public boolean compareAndDelete(StoreKey key, String value) {

        byte[] keyBytes = SafeEncoder.encode(key.toString());
        byte[] valueBytes = SafeEncoder.encode(value);

        Long result = redisCommands.eval(
                RedisScript.COMPARE_AND_DEL_BYTES,
                ReturnType.INTEGER,
                1,
                keyBytes, valueBytes);

        result = NullUtil.defaultIfNull(result, 0L);
        return result == 1;
    }

    @Override
    public String get(StoreKey key) {
        Object result = redisTemplate.opsForValue().get(key.toString());
        return result == null ? null : result.toString();
    }

    @Override
    public boolean exists(StoreKey key) {
        Boolean res = redisTemplate.hasKey(key.toString());
        return NullUtil.defaultIfNull(res, false);
    }

    @Override
    public boolean setNx(StoreKey key, String value, int leaseTime) {
        Boolean res = redisTemplate.opsForValue().setIfAbsent(key.toString(), value, leaseTime, TimeUnit.MILLISECONDS);
        return NullUtil.defaultIfNull(res, false);
    }
}
